
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <malloc.h>
#include "tcpclient.h"
#include "types.h"

typedef struct tcp_client
{
    int fd;
    SocketParser* parser;
    void* data;
} Client;

TcpClient tcpclient_new(SocketParser* parser)
{
    return tcpclient_from(-1, parser);
}

TcpClient tcpclient_from(int fd, SocketParser* parser)
{
    Client* ret = malloc(sizeof(Client));

    if( ret )
    {
        ret->fd = fd;
        ret->parser = parser;
        ret->data = NULL;
    }

    return (ret && ret->parser) ? ret : (free(ret), NULL);
}

// int tcpclient_sendmsg(TcpClient client, Message* msg)
// {
//     int ret = 0;
//     Client* c = (Client*)client;

//     if( c && msg )
//     {
//         int len = Message_Size(msg);
//         char* data = (char*)Message_H2N(msg);

//         ret = (send(c->fd, data, len, 0) != -1);

//         Message_N2H(msg);
//     }

//     return ret;
// }

int tcpclient_send_raw(TcpClient client, char* buf, int length)
{
    int ret = 0;
    Client* c = (Client*)client;
    
    if( c && buf )
    {
        ret = send(c->fd, buf, length, 0);
    }
    return ret;
}

Message* tcpclient_recv_msg(TcpClient client)
{
    Message* ret = NULL;
    Client* c = (Client*)client;

    if( c  )
    {
        //printf("recv start ... %d\n", c->fd);
        ret = c->parser->readfd(c->parser, c->fd);
    }

    return ret;
}

int tcpclient_recv_raw(TcpClient client, char* buf, int length)
{
    int ret = 0;
    Client* c = (Client*)client;

    if( c && buf )
    {   
        ret = recv(c->fd, buf, length, 0);
    }

    return ret;
}

int tcpclient_connect(TcpClient client, char* ip, int port)
{
    int ret = tcpclient_is_valid(client);
    Client* c = (Client*)client;
   
    if( !ret && ip && c && ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) != -1) )
    {
        struct sockaddr_in addr = {0};

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(ip);
        addr.sin_port = htons(port);
        ret = (connect(c->fd, (struct sockaddr*)&addr, sizeof(addr)) != -1);
    }
    
    return ret;
}

int tcpclient_is_valid(TcpClient client)
{
    int ret = 0;
    Client* c = (Client*)client;

    if( c )
    {
        struct tcp_info info = {0};
        int l = sizeof(info);

        getsockopt(c->fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&l);

        ret = (info.tcpi_state == TCP_ESTABLISHED);
    }
    
    return ret;
}

void tcpclient_close(TcpClient client)
{
    Client* c = (Client*)client;

    if( c )
    {
        close(c->fd);

        c->fd = -1;

        c->parser->reset();
    }
}

void tcpclient_del(TcpClient client)
{
    Client* c = (Client*)client;

    if( c )
    {
        tcpclient_close(c);
        
        free(c);
    }
}
